package com.rainbow.common.core.toolkit;

import cn.hutool.core.util.NumberUtil;
import org.apache.commons.lang3.ObjectUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.Objects;

/**
 * 金额计算工具类
 * @author 傅为地
 */
public final strictfp class MathCalculateUtil {

	// 默认运算精度
	private static final int DEF_SCALE = 10;

	/**
	 * 提供数据类型转换为BigDecimal
	 *
	 * @param object 原始数据
	 * @return BigDecimal
	 */
	public static BigDecimal bigDecimal(Object object) {
		if (ObjectUtils.isEmpty(object)) {
			throw new NullPointerException("the arguments can not be empty");
		}
		BigDecimal result;
		try {
			result = new BigDecimal(String.valueOf(object).replaceAll(",", ""));
		} catch (NumberFormatException e) {
			throw new NumberFormatException("Please give me a numeral.Not " + object);
		}
		return result;
	}

	/**
	 * 数组比较处理
	 * @param o1 参数1
	 * @param o2 参数2
	 * @return 比较结果
	 */
	public static int compare(Object o1, Object o2) {
		return bigDecimal(o1).setScale(DEF_SCALE, RoundingMode.HALF_UP).compareTo(bigDecimal(o1).setScale(DEF_SCALE, RoundingMode.HALF_UP));
	}

	/**
	 * 提供(相对)精确的加法运算。
	 *
	 * @param num1 被加数
	 * @param num2 加数
	 * @return 两个参数的和
	 */
	public static Double add(Object num1, Object num2) {
		BigDecimal result = bigDecimal(num1).add(bigDecimal(num2));
		return result.setScale(DEF_SCALE, RoundingMode.HALF_UP).doubleValue();
	}

	/**
	 * 提供(相对)精确的减法运算。
	 *
	 * @param num1 被减数
	 * @param num2 减数
	 * @return 两个参数的差
	 */
	public static Double subtract(Object num1, Object num2) {
		BigDecimal result = bigDecimal(num1).subtract(bigDecimal(num2));
		return result.setScale(DEF_SCALE, RoundingMode.HALF_UP).doubleValue();
	}

	/**
	 * 提供(相对)精确的乘法运算。
	 *
	 * @param num1 被乘数
	 * @param num2 乘数
	 * @return 两个参数的积
	 */
	public static Double multiply(Object num1, Object num2) {
		BigDecimal result = bigDecimal(num1).multiply(bigDecimal(num2));
		return result.setScale(DEF_SCALE, RoundingMode.HALF_UP).doubleValue();
	}

	/**
	 * 提供(相对)精确的除法运算，当发生除不尽的情况时，精度为10位，以后的数字四舍五入。
	 *
	 * @param num1 被除数
	 * @param num2 除数
	 * @return 两个参数的商
	 */
	public static Double divide(Object num1, Object num2) {
		if(ObjectUtils.isEmpty(num2)||Objects.equals(0,new BigDecimal(Objects.toString(num2,"0")).intValue())){
			throw new IllegalArgumentException("The divisor cannot be empty or zero");
		}
		return divide(num1, num2, DEF_SCALE);
	}

	/**
	 * 提供(相对)精确的除法运算。 当发生除不尽的情况时，由scale参数指定精度，以后的数字四舍五入。
	 *
	 * @param num1  被除数
	 * @param num2  除数
	 * @param scale 表示表示需要精确到小数点以后几位。
	 * @return 两个参数的商
	 */
	public static Double divide(Object num1, Object num2, Integer scale) {
		if (ObjectUtils.isEmpty(scale)) {
			scale = DEF_SCALE;
		}
		if(ObjectUtils.isEmpty(num2)||Objects.equals(0,new BigDecimal(Objects.toString(num2,"0")).intValue())){
			throw new IllegalArgumentException("The divisor cannot be empty or zero");
		}
		if (scale < 0) {
			throw new IllegalArgumentException("The scale must be a positive integer or zero");
		}
		BigDecimal result = bigDecimal(num1).divide(bigDecimal(num2), scale, RoundingMode.HALF_UP);
		return result.setScale(DEF_SCALE, RoundingMode.HALF_UP).doubleValue();
	}

	/**
	 * 提供精确的小数位四舍五入处理。
	 *
	 * @param num   需要四舍五入的数字
	 * @param scale 小数点后保留几位
	 * @return 四舍五入后的结果
	 */
	public static Double round(Object num, int scale) {
		if (scale < 0) {
			throw new IllegalArgumentException("The scale must be a positive integer or zero");
		}
		BigDecimal result = bigDecimal(num).divide(bigDecimal("1"), scale, RoundingMode.HALF_UP);
		return result.doubleValue();
	}

	/**
	 * 获取start到end区间的随机数,不包含start+end
	 *
	 * @param start 开始
	 * @param end   结束
	 * @return 返回随机数
	 */
	public static BigDecimal getRandom(int start, int end) {
		return new BigDecimal(start + Math.random() * end);
	}

	/**
	 * 格式化
	 * @param obj     数据
	 * @param pattern 格式化样式
	 * @return 返回格式化结果
	 */
	public static String format(Object obj, String pattern) {
		if (ObjectUtils.isEmpty(obj)) {
			return null;
		}
		if (ObjectUtils.isEmpty(pattern)) {
			pattern = "#";
		}
		return new DecimalFormat(pattern).format(bigDecimal(obj));
	}


	/**
	 * 数字百分比显示
	 * eg:23.65%
	 *
	 * @param object 入参
	 * @return 格式化结果
	 */
	public static String numberToPercent(Object object) {
		if (ObjectUtils.isEmpty(object)) {
			throw new IllegalArgumentException("The args must be not null!");
		}
		if (!NumberUtil.isNumber(Objects.toString(object))) {
			throw new IllegalArgumentException("The args must be the type of number!");
		}
		return new DecimalFormat("##.##%").format(bigDecimal(object));
	}

}
